package com.cloudlead.utils.async;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 默认异步任务服务
 * 
 * @author dean.lu
 * 
 */
public class SimpleAsyncTaskService implements AsyncTaskService {
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
	private final static int CPU_NUMBER = Runtime.getRuntime()
			.availableProcessors();
	// execute task thread pool size
	protected int taskThreadNum = CPU_NUMBER * 100;

	// max execute task thread pool size
	protected int maxTaskThreadNum = CPU_NUMBER * 2 * 200;

	// close service wait time
	protected long closeServiceWaitTime = 1000;

	protected int logIntervalTimeSeconds = 60;

	private final static AtomicLong totalTaskNum = new AtomicLong(0);
	private final static AtomicLong executingTaskNum = new AtomicLong(0);
	private final static AtomicLong executedTaskNum = new AtomicLong(0);

	protected BlockingQueue<Runnable> asyncTaskQueue;

	protected ExecutorService asyncTaskExecutor;

	protected boolean run = false;

	@Override
	public <V> AsyncTaskHandle<V> addTask(AsyncTask<V> task) {
		AsyncTaskHandle<V> asyncTaskHandle = new AsyncTaskHandle<V>(task);
		asyncTaskExecutor.execute(asyncTaskHandle);
		totalTaskNum.incrementAndGet();
		return asyncTaskHandle;
	}

	public void start() {
		if (!run) {
			run = true;
			// 初始化任务队列
			asyncTaskQueue = new LinkedBlockingQueue<Runnable>();
			asyncTaskExecutor = new AsyncTaskThreadPoolExecutor(taskThreadNum,
					maxTaskThreadNum, 0L, TimeUnit.MILLISECONDS,
					asyncTaskQueue, new AsyncTaskThreadFactory(),
					executingTaskNum, executedTaskNum);
//			Thread asyncTaskLogThread = new Thread() {
//
//				@Override
//				public void run() {
//					while (run) {
//						StringBuilder log = new StringBuilder();
//						log.append("\n--------------------Async Task Run Info------------------------");
//						log.append("\n                 In Queue Tasks  : "
//								+ getTaskRunInfo().getInQueueTasks());
//						log.append("\n                 Executing Tasks : "
//								+ getTaskRunInfo().getExecutingTasks());
//						log.append("\n                 Executed Tasks  : "
//								+ getTaskRunInfo().getExecutedTasks());
//						log.append("\n                 Total Tasks     : "
//								+ getTaskRunInfo().getTotalTasks());
//						log.append("\n--------------------Async Task Run Info------------------------");
//						logger.debug(log.toString());
//						try {
//							Thread.sleep(1000 * logIntervalTimeSeconds);
//						} catch (InterruptedException e) {
//						}
//					}
//				}
//
//			};
//
//			asyncTaskLogThread.start();

			logger.debug("init async task service success.");
		}
	}

	public void stop() {
		stop(closeServiceWaitTime);
	}

	public void stop(long waitTime) {
		if (run) {
			run = false;
			try {
				asyncTaskExecutor.awaitTermination(waitTime,
						TimeUnit.MILLISECONDS);
			} catch (InterruptedException e) {
				logger.error("", e);
			}
			asyncTaskExecutor.shutdown();
			logger.debug("Close async task service success.");
		}
	}

	@Override
	public TaskRunInfo getTaskRunInfo() {
		TaskRunInfo info = new TaskRunInfo();
		info.setTotalTasks(totalTaskNum.get());
		info.setExecutingTasks(executingTaskNum.get());
		info.setExecutedTasks(executedTaskNum.get());
		info.setInQueueTasks((long) asyncTaskQueue.size());
		return info;
	}

	/**
	 * 设置核心任务线程数量
	 * 
	 * @param taskThreadNum
	 */
	public void setTaskThreadNum(int taskThreadNum) {
		this.taskThreadNum = taskThreadNum;
	}

	/**
	 * 设置最大任务线程数量
	 * 
	 * @param maxTaskThreadNum
	 */
	public void setMaxTaskThreadNum(int maxTaskThreadNum) {
		this.maxTaskThreadNum = maxTaskThreadNum;
	}

	/**
	 * 设置关闭服务等待时间
	 * 
	 * @param closeServiceWaitTime
	 */
	public void setCloseServiceWaitTime(long closeServiceWaitTime) {
		this.closeServiceWaitTime = closeServiceWaitTime;
	}

	/**
	 * 设置日志间隔时间
	 * 
	 * @param logIntervalTimeSeconds
	 *            设定 logIntervalTimeSeconds 的值
	 */
	public void setLogIntervalTimeSeconds(int logIntervalTimeSeconds) {
		this.logIntervalTimeSeconds = logIntervalTimeSeconds;
	}

}
